#!/bin/bash

# 判断是否是root用户运行
if [[ `id -u` -ne 0 ]]; then
    echo "必须以root身份运行此脚本！"
    exit 1
fi

# 显示选择界面
function ChoiceInterface() {
    clear
    cat <<EOF
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                欢迎使用服务器上线优化功能
                                请选择优化操作
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1. 关闭SELINUX
2. 修改默认启动级别为3
3. 关闭不必要的开机启动项
4. SSHD优化
5. 时间同步服务
6. 修改系统连接数
7. 内核参数优化
10. 退出
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EOF
}

# 定义数字检测函数，判断是否输入回车或者非数字字符
function NumberLegalChecker() {
    num_wait2check=$1
    num_wait2check_unpacked=$(echo ${num_wait2check} | sed 's/[0-9]//g')
    
    if [[ ${num_wait2check_unpacked} == "-" ]]; then
        start_num=$(echo $num_wait2check | awk -F"-" '{print $1}')
        end_num=$(echo $num_wait2check | awk -F"-" '{print $2}')
        unpacked_numbers=$(eval echo "{$start_num..$end_num}")
        echo ${unpacked_numbers}
    elif [[ ! -n ${num_wait2check} || -n ${num_wait2check_unpacked} ]]; then
        echo -e "\033[34;5m输入错误，请重新输入！！！\033[0m"
        return 1
    else
        echo ${num_wait2check}
    fi
}

# 定义纯数字检测函数
function PureNumberLegalChecker() {
    num=$1
    num_filtered=$(echo ${num} | sed 's/[0-9]//g')
    if [[ -n $num && ! -n $num_filtered ]]; then
        return 0
    else
        echo -e "\033[34;5m输入错误，请重新输入！！！\033[0m"
        return 1
    fi
}

# 定义继续优化、返回主菜单、退出交互函数
function QuitOrReturn2Mian() {
    while true; do
        read -p "`echo -e '\033[33m请选择返回主菜单/退出 (M/Q): \033[0m'`" input_choice
        if [[ ! -n ${input_choice} ]]; then
            echo "输入错误，请重新选择！！！"
        elif [[ ${input_choice} == [Mm] ]]; then
            return
        elif [[ ${input_choice} == [Qq] ]]; then
            echo -e "\033[31;7m再见！！！ \033[0m"
            exit
        fi
    done
}

# 禁用SELINUX函数
function DisableSELINUX() {
    selinux_config_file=/etc/selinux/config
    echo "验证SELINUX配置文件。。。"
    if [[ -f ${selinux_config_file} ]]; then
        echo "配置文件验证成功！"
    else
        echo "配置文件验证失败"
        return 1
    fi

    se_status1=$(awk -F"=" '/^SELINUX=/ {print $2}' /etc/selinux/config)
    se_status2=$(getenforce)

    if [[ $se_status1 != 'disabled' ]]; then
        sed -i 's/\(SELINUX=\)enforcing/\1disabled/g' $selinux_config_file
        echo "修改了SELINUX配置文件，已置为Disabled，需要重启服务器"
    fi

    if [[ $se_status2 == 'Enforcing' ]]; then
        setenforce 0 && echo "已设置临时的SELINUX状态为permissive"
    fi

    echo "SELINUX已经成功修改完成"
    cmd=getenforce
    echo "执行命令: $cmd"
    echo "命令结果：`eval $cmd`"
    cmd="grep -e '^SELINUX=' ${selinux_config_file}"
    echo "执行命令: $cmd"
    echo "命令结果：`eval $cmd`"
    QuitOrReturn2Mian
}

# 修改默认启动级别函数
function ModifyDefaultRunlevel() {
    inittab_config_file=/etc/inittab
    echo "验证inittab配置文件。。。"
    if [[ -f ${inittab_config_file} ]]; then
        echo "配置文件验证成功！"
    else
        echo "配置文件验证失败"
        return 1
    fi
    
    sed -i 's/\(id:\)[0-9]\(:initdefault:\)/\13\2/g' ${inittab_config_file}
    echo "默认启动级别已经成功修改完成"
    cmd="grep -e '^id:[0-9]:initdefault:' ${inittab_config_file}"
    echo "执行命令:  $cmd"
    echo "命令结果：`eval $cmd`"
    QuitOrReturn2Mian
}

# 开机启动项优化函数
function AutostartOptimization() {
    current_autostart_inventory=($(chkconfig --list | grep '3:on' | awk '{print $1}'))
    user_choice_inventory=()
    
    function InactivePrintAutostartItem() {
        clear
        for order_number in $(seq 0 $(( ${#current_autostart_inventory[@]} - 1 ))); do
            choice_boolen=false
            for choice_number in ${user_choice_inventory[@]}; do
                if [[ ${order_number} -eq ${choice_number} ]]; then
                    choice_boolen=true
                fi
            done
            if ${choice_boolen}; then
                printf "\033[41;36m%-3s-->%-17s\033[0m" ${order_number} ${current_autostart_inventory[${order_number}]}
            else
                printf "%-3s-->%-17s" ${order_number} ${current_autostart_inventory[${order_number}]}
            fi
            if [[ $(((${order_number}+1)%4)) -eq 0 ]]; then
                printf "\n"
            fi
        done
        echo
        echo -e "已选择开机启动项 \033[41;36m      \033[0m"
        if [[ ${#illegal_user_choice_inventory[@]} -gt 0 ]]; then
            echo -e "\033[35;1m未操作开机启动项   ${illegal_user_choice_inventory[*]} \033[0m"
        fi
    }
    
    function disable_startup() {
        for item in ${current_autostart_inventory[@]}; do
            chkconfig --level 3 $item off
        done
        for allow_autostart_number in ${user_choice_inventory[@]}; do
            chkconfig --level 3 ${current_autostart_inventory[${allow_autostart_number}]} on
        done
        echo "查看现在的启动项列表"
        cmd="chkconfig --list | grep 3:on"
        echo "执行命令: $cmd"
        echo -e "命令结果: \n`eval $cmd`"
    }
    
    while true; do
        InactivePrintAutostartItem
        
        while true; do
            echo "请选择需要开机自动启动的项(未选择的将被禁止启动,请输入每个服务所代表的数字)"
            read -p "支持多选，支持连续模式，如3-11，请输入: " allow_autostart_variables
            
            while [[ ! -n ${allow_autostart_variables} ]]; do
                echo "请选择需要开机自动启动的项(未选择的将被禁止启动,请输入每个服务所代表的数字)"
                read -p "支持多选，请输入: " allow_autostart_variables
            done
            
            allow_autostart_inventory=($(echo ${allow_autostart_variables} | sed 's/[][!#$%&*+,./:;<=>?@\^_{|}~]/\ /g'))
            allow_autostart_unpacked_inventory=()
            
            for single_allow_autostart_item in ${allow_autostart_inventory[*]}; do
                result_after_num_checker=$(NumberLegalChecker ${single_allow_autostart_item})
                if [[ -n $result_after_num_checker ]]; then
                    allow_autostart_unpacked_inventory=("${allow_autostart_unpacked_inventory[@]}" $result_after_num_checker)
                else
                    continue
                fi
            done
            
            autostart_number_inventory=($(eval echo {0..$(( ${#current_autostart_inventory[@]} - 1 ))}))
            legal_autostart_num_inventory=($(echo ${allow_autostart_unpacked_inventory[*]} ${autostart_number_inventory[*]} | sed 's/\ /\n/g' | sort | uniq -d | tr "\n" " "))
            illegal_autostart_num_inventory=($(echo ${allow_autostart_unpacked_inventory[*]} ${autostart_number_inventory[*]} ${autostart_number_inventory[*]} | sed 's/\ /\n/g' | sort | uniq -u | tr "\n" " "))
            user_choice_inventory=("${legal_autostart_num_inventory[@]}" ${user_choice_inventory[@]})
            illegal_user_choice_inventory=(${illegal_autostart_num_inventory[@]})
            InactivePrintAutostartItem
            break
        done
        
        while true; do
            read -p "是否继续选择启用的开机启动项 是/否(应用)/删除（Y/N/D）: " con_or_apply
            if [[ ! -n ${con_or_apply} ]]; then
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            elif [[ ${con_or_apply} == [Yy] ]]; then
                break
            elif [[ ${con_or_apply} == [Nn] ]]; then
                read -p "是否应用 是/否（Y/N）: " yes_no_apply
                
                while true; do
                    if [[ ! -n ${yes_no_apply} ]]; then
                        echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
                    elif [[ ${yes_no_apply} == [Yy] ]]; then
                        echo "开始执行应用所选择的启动项"
                        disable_startup
                        break
                    elif [[ ${yes_no_apply} == [Nn] ]]; then
                        break
                    else
                        echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
                    fi
                    read -p "是否应用 是/否（Y/N）: " yes_no_apply
                done
                QuitOrReturn2Mian
                return
            elif [[ ${con_or_apply} == [Dd] ]]; then
                read -p "请输入要移除的启动项序列号： " require2remove_num_variables
                
                while [[ ! -n ${require2remove_num_variables} ]]; do
                    read -p "请输入要移除的启动项序列号(支持多选 支持连接符-): " require2remove_num_variables
                done
                
                removing_num_inventory=($(echo ${require2remove_num_variables} | sed 's/[][!#$%&*+,./:;<=>?@\^_{|}~]/\ /g'))
                removing_num_unpacked_inventory=()
                
                for single_removing_numt_item in ${removing_num_inventory[*]}; do
                    result_after_num_checker=$(NumberLegalChecker ${single_removing_numt_item})
                    if [[ -n $result_after_num_checker ]]; then
                        removing_num_unpacked_inventory=("${removing_num_unpacked_inventory[@]}" $result_after_num_checker)
                    else
                        continue
                    fi
                done
                
                legal_removing_inventory=($(echo ${removing_num_unpacked_inventory[*]} ${user_choice_inventory[*]} | sed 's/\ /\n/g' | sort | uniq -d | tr "\n" " "))
                illegal_removing_inventory=($(echo ${removing_num_unpacked_inventory[*]} ${user_choice_inventory[*]} ${user_choice_inventory[*]} | sed 's/\ /\n/g' | sort | uniq -u | tr "\n" " "))
                user_choice_inventory=($(echo ${legal_removing_inventory[*]} ${user_choice_inventory[*]} | sed 's/\ /\n/g' | sort | uniq -u | tr "\n" " "))
                illegal_user_choice_inventory=(${illegal_removing_inventory[@]})
                InactivePrintAutostartItem
                echo "已成功移除 ${legal_removing_inventory[*]}"
            else
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            fi
        done
    done
}

# SSH优化函数
function SshOptimization() {
    ssh_config_file=/etc/ssh/sshd_config
    echo "验证sshd配置文件。。。"
    if [[ -f ${ssh_config_file} ]]; then
        echo "配置文件验证成功！"
    else
        echo "配置文件验证失败"
        return 1
    fi

    function DisableUseDNS() {
        sed -i 's/#*\(UseDNS\ \)yes/\1no/g' ${ssh_config_file}
        sed -i 's/\(GSSAPIAuthentication\ \)yes/\1no/g' ${ssh_config_file}
        cmd="grep UseDNS ${ssh_config_file}"
        echo "执行命令: $cmd"
        echo "执行结果: `eval $cmd`"
        cmd="grep GSSAPIAuthentication ${ssh_config_file}"
        echo "执行命令: $cmd"
        echo "执行结果: `eval $cmd`"
    }

    function ChangeSshPort() {
        port=$1
        echo "正在更改SSH默认端口号。。。"
        sed -i "s/#*\(Port\ *\)[0-9]*$/\1$port/g" ${ssh_config_file}
        cmd="grep -E ^Port ${ssh_config_file}"
        echo "执行命令: $cmd"
        echo "执行结果: `eval $cmd`"
    }

    function PermitRootLogin() {
        permit_root_login=$1
        echo "正在修改是否允许root ssh登录。。。"
        sed -i "s/#*\(PermitRootLogin\ *\).*$/\1$permit_root_login/g" ${ssh_config_file}
        cmd="grep -E ^#*PermitRootLogin ${ssh_config_file}"
        echo "执行命令: $cmd"
        echo "执行结果: `eval $cmd`"
    }

    function InteractiveDisableUseDNS() {
        read -p "是否启用SSH加速 是/否  (Y/N): " speedup_yes_no
        
        while true; do
            if [[ ! -n ${speedup_yes_no} ]]; then
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            elif [[ ${speedup_yes_no} == [Yy] ]]; then
                echo "启用SSH加速功能"
                DisableUseDNS
                return
            elif [[ ${speedup_yes_no} == [Nn] ]]; then
                return
            else
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            fi
            read -p "是否启用SSH加速 是/否  (Y/N): " speedup_yes_no
        done
    }

    function InteracticeChangeSshPort() {
        read -p "是否修改SSH端口 是/否  (Y/N): " sshport_yes_no
        
        while true; do
            if [[ ! -n ${sshport_yes_no} ]]; then
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            elif [[ ${sshport_yes_no} == [Yy] ]]; then
                while true; do
                    read -p "请输入要修改的端口号：" port
                    
                    while ! PureNumberLegalChecker ${port}; do
                        read -p "请输入要修改的端口号：" port
                    done
                    
                    if [[ $port -gt 0 && $port -lt 65535 ]]; then
                        known_service_filter=$(grep -E "[[:space:]]$port/[tcp|udp]" /etc/services)
                        
                        if [[ -n ${known_service_filter} ]]; then
                            echo -e "这个端口已经有服务在使用，\n ${known_service_filter}\n"
                            read -p "是否继续使用这个端口? (Y/N)" port_confirm
                            
                            while true; do
                                if [[ ! -n ${port_confirm} ]]; then
                                    echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
                                elif [[ ${port_confirm} == [Yy] ]]; then
                                    ChangeSshPort $port
                                    return
                                elif [[ ${port_confirm} == [Nn] ]]; then
                                    break
                                else
                                    echo -e "\033[34;5m输入错误，请重新输入！！！\033[0m"
                                    continue
                                fi
                            done
                        else
                            ChangeSshPort $port
                            return
                        fi
                    else
                        echo -e "\033[34;5m输入错误，端口范围需在0~65535 请重新输入！！！\033[0m"
                    fi
                done
            elif [[ ${sshport_yes_no} == [Nn] ]]; then
                return
            else
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            fi
            read -p "是否修改SSH端口 是/否  (Y/N): " sshport_yes_no
        done
    }

    function InteractivePermitRootLogin() {
        read -p "是否允许Root通过SSH登录 是/否  (Y/N): " root_login_yes_no
        
        while true; do
            if [[ ! -n ${root_login_yes_no} ]]; then
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            elif [[ ${root_login_yes_no} == [Yy] ]]; then
                echo "允许root登录"
                PermitRootLogin "yes"
                return
            elif [[ ${root_login_yes_no} == [Nn] ]]; then
                echo "禁止root登录"
                PermitRootLogin "no"
                return
            else
                echo -e "\033[34;5m输入错误，请重新选择！！！\033[0m"
            fi
            read -p "是否允许Root通过SSH登录 是/否  (Y/N): " root_login_yes_no
        done
    }

    InteractiveDisableUseDNS
    InteracticeChangeSshPort
    InteractivePermitRootLogin
    systemctl restart sshd > /dev/null
    QuitOrReturn2Mian
}

# 时间同步服务函数
function TimeSynchronization() {
    echo "此功能待开发"
    QuitOrReturn2Mian
}

# 修改系统连接数函数
function ModifySystemResourceLimit() {
    echo "此功能待开发"
    QuitOrReturn2Mian
}

# 内核参数优化函数
function KernelParameterOptimization() {
    echo "此功能待开发"
    QuitOrReturn2Mian
}

# 主循环
while ChoiceInterface; do
    read -p "请输入你的选择:" choice
    NumberLegalChecker ${choice} || continue
    case $choice in
        1) DisableSELINUX ;;
        2) ModifyDefaultRunlevel ;;
        3) AutostartOptimization ;;
        4) SshOptimization ;;
        5) TimeSynchronization ;;
        6) ModifySystemResourceLimit ;;
        7) KernelParameterOptimization ;;
        10) exit 0 ;;
        *) echo "选择错误，请重新选择！" ;;
    esac
done
